{ "cells": [ { "cell_type": "markdown", "id": "a8fba70d", "metadata": {}, "source": [ "(sec-dataset-examples)=\n", "# Quantify dataset - examples\n", "\n", "```{seealso}\n", "The complete source code of this tutorial can be found in\n", "\n", "{nb-download}`Quantify dataset - examples.ipynb`\n", "```" ] }, { "cell_type": "code", "execution_count": null, "id": "a7db0795", "metadata": { "mystnb": { "code_prompt_show": "Imports and auxiliary utilities" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "from pathlib import Path\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import xarray as xr\n", "from rich import pretty\n", "\n", "import quantify_core.data.dataset_attrs as dattrs\n", "from quantify_core.analysis.calibration import rotate_to_calibrated_axis\n", "from quantify_core.analysis.fitting_models import exp_decay_func\n", "from quantify_core.data import handling as dh\n", "from quantify_core.utilities import dataset_examples\n", "from quantify_core.utilities.examples_support import (\n", " mk_iq_shots,\n", " mk_trace_for_iq_shot,\n", " mk_trace_time,\n", " round_trip_dataset,\n", ")\n", "from quantify_core.utilities.inspect_utils import display_source_code\n", "from quantify_core.visualization.mpl_plotting import (\n", " plot_complex_points,\n", " plot_xr_complex,\n", " plot_xr_complex_on_plane,\n", ")\n", "\n", "pretty.install()\n", "\n", "dh.set_datadir(Path.home() / \"quantify-data\") # change me!" ] }, { "cell_type": "markdown", "id": "39e2529b", "metadata": {}, "source": [ "In this page we explore a series of datasets that comply with the {ref}`Quantify dataset specification `.\n", "\n", "## 2D dataset example\n", "\n", "We use the {func}`~quantify_core.utilities.dataset_examples.mk_two_qubit_chevron_dataset`\n", "to generate our exemplary dataset. Its source code is conveniently displayed in the\n", "drop-down below." ] }, { "cell_type": "code", "execution_count": null, "id": "4c6409a9", "metadata": { "mystnb": { "code_prompt_show": "Source code for generating mock Chevron dataset" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "display_source_code(dataset_examples.mk_two_qubit_chevron_dataset)" ] }, { "cell_type": "code", "execution_count": null, "id": "7d623919", "metadata": {}, "outputs": [], "source": [ "dataset = dataset_examples.mk_two_qubit_chevron_dataset()\n", "\n", "assert dataset == round_trip_dataset(dataset) # confirm read/write\n", "dataset" ] }, { "cell_type": "markdown", "id": "4b866501", "metadata": {}, "source": [ "The data within this dataset can be easily visualized using xarray facilities,\n", "however, we first need to convert the Quantify dataset to a \"gridded\" version with the {func}`~quantify_core.data.handling.to_gridded_dataset` function as \n", "shown below.\n", "\n", "Since our dataset contains multiple repetitions of the same experiment, it is convenient\n", "to visualize them on different plots." ] }, { "cell_type": "code", "execution_count": null, "id": "95035601", "metadata": {}, "outputs": [], "source": [ "dataset_gridded = dh.to_gridded_dataset(\n", " dataset,\n", " dimension=\"main_dim\",\n", " coords_names=dattrs.get_main_coords(dataset),\n", ")\n", "dataset_gridded.pop_q0.plot.pcolormesh(x=\"amp\", col=\"repetitions\")\n", "_ = dataset_gridded.pop_q1.plot.pcolormesh(x=\"amp\", col=\"repetitions\")" ] }, { "cell_type": "markdown", "id": "8143b28c", "metadata": {}, "source": [ "In xarray, among other features, it is possible to average along a dimension which can\n", "be very convenient to average out some of the noise:" ] }, { "cell_type": "code", "execution_count": null, "id": "26ce1ae1", "metadata": {}, "outputs": [], "source": [ "_ = dataset_gridded.pop_q0.mean(dim=\"repetitions\").plot(x=\"amp\")" ] }, { "cell_type": "markdown", "id": "365794d7", "metadata": {}, "source": [ "A repetitions dimension can be indexed by a coordinate such that we can have some\n", "specific label for each of our repetitions. To showcase this, we will modify the previous\n", "dataset by merging it with a dataset containing the relevant extra information." ] }, { "cell_type": "code", "execution_count": null, "id": "42912255", "metadata": {}, "outputs": [], "source": [ "coord_dims = (\"repetitions\",)\n", "coord_values = [\"A\", \"B\", \"C\", \"D\", \"E\"]\n", "dataset_indexed_rep = xr.Dataset(coords=dict(repetitions=(coord_dims, coord_values)))\n", "\n", "dataset_indexed_rep" ] }, { "cell_type": "code", "execution_count": null, "id": "239aed59", "metadata": {}, "outputs": [], "source": [ "# merge with the previous dataset\n", "dataset_rep = dataset_gridded.merge(dataset_indexed_rep, combine_attrs=\"drop_conflicts\")\n", "\n", "assert dataset_rep == round_trip_dataset(dataset_rep) # confirm read/write\n", "\n", "dataset_rep" ] }, { "cell_type": "markdown", "id": "3e0d82c9", "metadata": {}, "source": [ "Now we can select a specific repetition by its coordinate, in this case a string label." ] }, { "cell_type": "code", "execution_count": null, "id": "65a14e83", "metadata": {}, "outputs": [], "source": [ "_ = dataset_rep.pop_q0.sel(repetitions=\"E\").plot(x=\"amp\")" ] }, { "cell_type": "markdown", "id": "012ce4e3", "metadata": {}, "source": [ "## T1 dataset examples\n", "\n", "The T1 experiment is one of the most common quantum computing experiments.\n", "Here we explore how the datasets for such an experiment, for a transmon qubit, can be\n", "stored using the Quantify dataset with increasing levels of data detail.\n", "\n", "We start with the most simple format that contains only processed (averaged) measurements\n", "and finish with a dataset containing the raw digitized signals from the transmon readout\n", "during a T1 experiment.\n", "\n", "We use a few auxiliary functions to generate, manipulate and plot the data of the\n", "examples that follow:\n", "\n", "- {func}`quantify_core.utilities.examples_support.mk_iq_shots`\n", "- {func}`quantify_core.utilities.examples_support.mk_trace_time`\n", "- {func}`quantify_core.utilities.examples_support.mk_trace_for_iq_shot`\n", "- {func}`quantify_core.analysis.fitting_models.exp_decay_func`\n", "\n", "Below you can find the source-code of the most important ones and a few usage\n", "examples in order to gain some intuition for the mock data." ] }, { "cell_type": "code", "execution_count": null, "id": "bb93d8f4", "metadata": { "mystnb": { "code_prompt_show": "Source code for generating mock data" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "for func in (mk_iq_shots, mk_trace_time, mk_trace_for_iq_shot):\n", " display_source_code(func)" ] }, { "cell_type": "code", "execution_count": null, "id": "e796f261", "metadata": {}, "outputs": [], "source": [ "ground = -0.2 + 0.65j\n", "excited = 0.7 - 0.4j\n", "centers = ground, excited\n", "sigmas = [0.1] * 2\n", "\n", "shots = mk_iq_shots(\n", " num_shots=256,\n", " sigmas=sigmas,\n", " centers=centers,\n", " probabilities=[0.4, 1 - 0.4],\n", ")\n", "\n", "plt.hexbin(shots.real, shots.imag)\n", "plt.xlabel(\"I\")\n", "plt.ylabel(\"Q\")\n", "_ = plot_complex_points(centers, ax=plt.gca())" ] }, { "cell_type": "code", "execution_count": null, "id": "c448495a", "metadata": {}, "outputs": [], "source": [ "time = mk_trace_time()\n", "trace = mk_trace_for_iq_shot(shots[0])\n", "\n", "fig, ax = plt.subplots(1, 1, figsize=(12, 12 / 1.61 / 2))\n", "ax.plot(time * 1e6, trace.imag, \".-\", label=\"I-quadrature\")\n", "ax.plot(time * 1e6, trace.real, \".-\", label=\"Q-quadrature\")\n", "ax.set_xlabel(\"Time [µs]\")\n", "ax.set_ylabel(\"Amplitude [V]\")\n", "_ = ax.legend()" ] }, { "cell_type": "markdown", "id": "7e6fed2e", "metadata": {}, "source": [ "First, we define a few parameters of our mock qubit and mock data acquisition." ] }, { "cell_type": "code", "execution_count": null, "id": "a0873c0f", "metadata": {}, "outputs": [], "source": [ "# parameters of our qubit model\n", "tau = 30e-6\n", "ground = -0.2 + 0.65j # ground state on the IQ-plane\n", "excited = 0.7 - 0.4j # excited state on the IQ-plane\n", "centers = ground, excited\n", "sigmas = [0.1] * 2 # sigma, NB in general not the same for both state\n", "\n", "# mock of data acquisition configuration\n", "# NB usually at least 1000+ shots are taken, here we use less for faster code execution\n", "num_shots = 256\n", "# time delays between exciting the qubit and measuring its state\n", "t1_times = np.linspace(0, 120e-6, 30)\n", "\n", "# NB this are the ideal probabilities from repeating the measurement many times for a\n", "# qubit with a lifetime given by tau\n", "probabilities = exp_decay_func(t=t1_times, tau=tau, offset=0, n_factor=1, amplitude=1)\n", "\n", "# Ideal experiment result\n", "plt.ylabel(\"|1> probability\")\n", "plt.suptitle(\"Typical processed data of a T1 experiment\")\n", "plt.plot(t1_times * 1e6, probabilities, \".-\")\n", "_ = plt.xlabel(\"Time [µs]\")" ] }, { "cell_type": "code", "execution_count": null, "id": "7ff3baf1", "metadata": {}, "outputs": [], "source": [ "# convenience dict with the mock parameters\n", "mock_conf = dict(\n", " num_shots=num_shots,\n", " centers=centers,\n", " sigmas=sigmas,\n", " t1_times=t1_times,\n", " probabilities=probabilities,\n", ")" ] }, { "cell_type": "markdown", "id": "b2d4ead4", "metadata": {}, "source": [ "### T1 experiment averaged\n", "\n", "In this first example, we generate the individual measurement shots and average them,\n", "similar to what some instruments are capable of doing directly in the hardware.\n", "\n", "Here is how we store this data in the dataset along with the coordinates of these\n", "datapoints:" ] }, { "cell_type": "code", "execution_count": null, "id": "f3501d05", "metadata": { "mystnb": { "code_prompt_show": "Source code for generating the dataset below" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "display_source_code(dataset_examples.mk_t1_av_dataset)" ] }, { "cell_type": "code", "execution_count": null, "id": "c8c55061", "metadata": {}, "outputs": [], "source": [ "dataset = dataset_examples.mk_t1_av_dataset(**mock_conf)\n", "assert dataset == round_trip_dataset(dataset) # confirm read/write\n", "\n", "dataset" ] }, { "cell_type": "code", "execution_count": null, "id": "9a2dbf79", "metadata": {}, "outputs": [], "source": [ "dataset.q0_iq_av.shape, dataset.q0_iq_av.dtype" ] }, { "cell_type": "code", "execution_count": null, "id": "a3f589a9", "metadata": {}, "outputs": [], "source": [ "dataset_gridded = dh.to_gridded_dataset(\n", " dataset,\n", " dimension=\"main_dim\",\n", " coords_names=dattrs.get_main_coords(dataset),\n", ")\n", "dataset_gridded" ] }, { "cell_type": "code", "execution_count": null, "id": "45038c53", "metadata": { "mystnb": { "code_prompt_show": "Source code for plotting utilities" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "display_source_code(plot_xr_complex)\n", "display_source_code(plot_xr_complex_on_plane)" ] }, { "cell_type": "code", "execution_count": null, "id": "5acb8de8", "metadata": {}, "outputs": [], "source": [ "plot_xr_complex(dataset_gridded.q0_iq_av)\n", "fig, ax = plot_xr_complex_on_plane(dataset_gridded.q0_iq_av)\n", "_ = plot_complex_points(centers, ax=ax)" ] }, { "cell_type": "markdown", "id": "3a9a2d7f", "metadata": {}, "source": [ "### T1 experiment averaged with calibration points\n", "\n", "It is common for many experiments to require calibration data in order to interpret the\n", "results. Often, these calibration data points have different array shapes. E.g. it can be\n", "just two simple data points corresponding to the ground and excited states of our\n", "transmon.\n", "\n", "To accommodate this data in the dataset we make use of a secondary dimension along which\n", "the variables and its coordinate will lie along.\n", "\n", "Additionally, since the secondary variable and coordinate used for calibration can have\n", "arbitrary names and relate to other variables in more complex ways, we specify this\n", "relationship in the dataset attributes\n", "(see {class}`~quantify_core.data.dataset_attrs.QDatasetIntraRelationship`).\n", "This information can be used later, for example, to run an appropriate analysis on this\n", "dataset." ] }, { "cell_type": "code", "execution_count": null, "id": "bc2ce765", "metadata": { "mystnb": { "code_prompt_show": "Source code for generating the dataset below" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "display_source_code(dataset_examples.mk_t1_av_with_cal_dataset)" ] }, { "cell_type": "code", "execution_count": null, "id": "cbd22722", "metadata": {}, "outputs": [], "source": [ "dataset = dataset_examples.mk_t1_av_with_cal_dataset(**mock_conf)\n", "assert dataset == round_trip_dataset(dataset) # confirm read/write\n", "\n", "dataset" ] }, { "cell_type": "code", "execution_count": null, "id": "8132a26b", "metadata": {}, "outputs": [], "source": [ "dattrs.get_main_dims(dataset), dattrs.get_secondary_dims(dataset)" ] }, { "cell_type": "code", "execution_count": null, "id": "44be374f", "metadata": {}, "outputs": [], "source": [ "dataset.relationships" ] }, { "cell_type": "markdown", "id": "69094ad3", "metadata": {}, "source": [ "As before the coordinates can be set to index the variables that lie along the same\n", "dimensions:" ] }, { "cell_type": "code", "execution_count": null, "id": "20be5290", "metadata": {}, "outputs": [], "source": [ "dataset_gridded = dh.to_gridded_dataset(\n", " dataset,\n", " dimension=\"main_dim\",\n", " coords_names=dattrs.get_main_coords(dataset),\n", ")\n", "dataset_gridded = dh.to_gridded_dataset(\n", " dataset_gridded,\n", " dimension=\"cal_dim\",\n", " coords_names=dattrs.get_secondary_coords(dataset_gridded),\n", ")\n", "dataset_gridded" ] }, { "cell_type": "code", "execution_count": null, "id": "94386fe9", "metadata": {}, "outputs": [], "source": [ "fig = plt.figure(figsize=(8, 5))\n", "\n", "ax = plt.subplot2grid((1, 10), (0, 0), colspan=9, fig=fig)\n", "plot_xr_complex(dataset_gridded.q0_iq_av, ax=ax)\n", "\n", "ax_calib = plt.subplot2grid((1, 10), (0, 9), colspan=1, fig=fig, sharey=ax)\n", "for i, color in zip(\n", " range(2), [\"C0\", \"C1\"]\n", "): # plot each calibration point with same color\n", " dataset_gridded.q0_iq_av_cal.real[i : i + 1].plot.line(\n", " marker=\"o\", ax=ax_calib, linestyle=\"\", color=color\n", " )\n", " dataset_gridded.q0_iq_av_cal.imag[i : i + 1].plot.line(\n", " marker=\"o\", ax=ax_calib, linestyle=\"\", color=color\n", " )\n", "ax_calib.yaxis.set_label_position(\"right\")\n", "ax_calib.yaxis.tick_right()\n", "\n", "fig, ax = plot_xr_complex_on_plane(dataset_gridded.q0_iq_av)\n", "_ = plot_complex_points(dataset_gridded.q0_iq_av_cal.values, ax=ax)" ] }, { "cell_type": "markdown", "id": "afed9f4e", "metadata": {}, "source": [ "We can use the calibration points to normalize the data and obtain the typical T1 decay.\n", "\n", "### Data rotation and normalization utilities\n", "\n", "The normalization of the calibration points can be achieved as follows.\n", "Several of the\n", "{mod}`single-qubit time-domain analyses `\n", "provided use this under the hood.\n", "The result is that most of the information will now be contained within the same\n", "quadrature." ] }, { "cell_type": "code", "execution_count": null, "id": "39458494", "metadata": {}, "outputs": [], "source": [ "rotated_and_normalized = rotate_to_calibrated_axis(\n", " dataset_gridded.q0_iq_av.values, *dataset_gridded.q0_iq_av_cal.values\n", ")\n", "rotated_and_normalized_da = xr.DataArray(dataset_gridded.q0_iq_av)\n", "rotated_and_normalized_da.values = rotated_and_normalized\n", "rotated_and_normalized_da.attrs[\"long_name\"] = \"|1> Population\"\n", "rotated_and_normalized_da.attrs[\"units\"] = \"\"\n", "_ = plot_xr_complex(rotated_and_normalized_da)" ] }, { "cell_type": "markdown", "id": "1ea18eeb", "metadata": {}, "source": [ "### T1 experiment storing all shots\n", "\n", "Now we will include in the dataset all the single qubit states (shot) for each\n", "individual measurement." ] }, { "cell_type": "code", "execution_count": null, "id": "e46844e8", "metadata": { "mystnb": { "code_prompt_show": "Source code for generating the dataset below" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "display_source_code(dataset_examples.mk_t1_shots_dataset)" ] }, { "cell_type": "code", "execution_count": null, "id": "9e57023f", "metadata": {}, "outputs": [], "source": [ "dataset = dataset_examples.mk_t1_shots_dataset(**mock_conf)\n", "dataset" ] }, { "cell_type": "code", "execution_count": null, "id": "0c2357c2", "metadata": {}, "outputs": [], "source": [ "dataset_gridded = dh.to_gridded_dataset(\n", " dataset,\n", " dimension=\"main_dim\",\n", " coords_names=dattrs.get_main_coords(dataset),\n", ")\n", "dataset_gridded = dh.to_gridded_dataset(\n", " dataset_gridded,\n", " dimension=\"cal_dim\",\n", " coords_names=dattrs.get_secondary_coords(dataset_gridded),\n", ")\n", "dataset_gridded" ] }, { "cell_type": "markdown", "id": "f14d060f", "metadata": {}, "source": [ "In this dataset we have both the averaged values and all the shots. The averaged values\n", "can be plotted in the same way as before." ] }, { "cell_type": "code", "execution_count": null, "id": "eff69184", "metadata": {}, "outputs": [], "source": [ "_ = plot_xr_complex(dataset_gridded.q0_iq_av)\n", "_, ax = plot_xr_complex_on_plane(dataset_gridded.q0_iq_av)\n", "_ = plot_complex_points(dataset_gridded.q0_iq_av_cal.values, ax=ax)" ] }, { "cell_type": "markdown", "id": "b1d27387", "metadata": {}, "source": [ "Here we focus on inspecting how the individual shots are distributed on the IQ plane\n", "for some particular `Time` values.\n", "\n", "Note that we are plotting the calibration points as well." ] }, { "cell_type": "code", "execution_count": null, "id": "fbcc3811", "metadata": {}, "outputs": [], "source": [ "chosen_time_values = [\n", " t1_times[1], # second value selected otherwise we won't see both centers\n", " t1_times[len(t1_times) // 5], # a value close to the end of the experiment\n", "]\n", "for t_example in chosen_time_values:\n", " shots_example = (\n", " dataset_gridded.q0_iq_shots.real.sel(t1_time=t_example),\n", " dataset_gridded.q0_iq_shots.imag.sel(t1_time=t_example),\n", " )\n", " plt.hexbin(*shots_example)\n", " plt.xlabel(\"I\")\n", " plt.ylabel(\"Q\")\n", " calib_0 = dataset_gridded.q0_iq_av_cal.sel(cal=\"|0>\")\n", " calib_1 = dataset_gridded.q0_iq_av_cal.sel(cal=\"|1>\")\n", " plot_complex_points([calib_0, calib_1], ax=plt.gca())\n", " plt.suptitle(f\"Shots for t = {t_example:.5f} [s]\")\n", " plt.show()" ] }, { "cell_type": "markdown", "id": "ea8da075", "metadata": {}, "source": [ "We can collapse (average along) the `repetitions` dimension:" ] }, { "cell_type": "code", "execution_count": null, "id": "c321a4a3", "metadata": {}, "outputs": [], "source": [ "q0_iq_shots_mean = dataset_gridded.q0_iq_shots.mean(dim=\"repetitions\", keep_attrs=True)\n", "plot_xr_complex(q0_iq_shots_mean)\n", "_, ax = plot_xr_complex_on_plane(q0_iq_shots_mean)\n", "_ = plot_complex_points(centers, ax=ax)" ] }, { "cell_type": "markdown", "id": "3ca2bdcc", "metadata": {}, "source": [ "(sec-dataset-t1-traces)=\n", "\n", "### T1 experiment storing digitized signals for all shots\n", "\n", "Finally, in addition to the individual shots we will store all the digitized readout\n", "signals that are required to obtain the previous measurement results." ] }, { "cell_type": "code", "execution_count": null, "id": "078c7002", "metadata": { "mystnb": { "code_prompt_show": "Source code for generating the dataset below" }, "tags": [ "hide-cell" ] }, "outputs": [], "source": [ "display_source_code(dataset_examples.mk_t1_traces_dataset)" ] }, { "cell_type": "code", "execution_count": null, "id": "ceb30e07", "metadata": {}, "outputs": [], "source": [ "dataset = dataset_examples.mk_t1_traces_dataset(**mock_conf)\n", "assert dataset == round_trip_dataset(dataset) # confirm read/write\n", "\n", "dataset" ] }, { "cell_type": "code", "execution_count": null, "id": "c5d7d06c", "metadata": {}, "outputs": [], "source": [ "dataset.q0_traces.shape, dataset.q0_traces_cal.shape" ] }, { "cell_type": "code", "execution_count": null, "id": "afb96381", "metadata": {}, "outputs": [], "source": [ "dataset_gridded = dh.to_gridded_dataset(\n", " dataset,\n", " dimension=\"main_dim\",\n", " coords_names=[\"t1_time\"],\n", ")\n", "dataset_gridded = dh.to_gridded_dataset(\n", " dataset_gridded,\n", " dimension=\"cal_dim\",\n", " coords_names=[\"cal\"],\n", ")\n", "dataset_gridded = dh.to_gridded_dataset(\n", " dataset_gridded, dimension=\"trace_dim\", coords_names=[\"trace_time\"]\n", ")\n", "dataset_gridded" ] }, { "cell_type": "code", "execution_count": null, "id": "e86d695e", "metadata": {}, "outputs": [], "source": [ "dataset_gridded.q0_traces.shape, dataset_gridded.q0_traces.dims" ] }, { "cell_type": "markdown", "id": "f8b5e3e7", "metadata": {}, "source": [ "All the previous data is also present, but in this dataset we can inspect the IQ signal\n", "for each individual shot. Let's inspect the signal of shot number 123 of the last\n", "\"point\" of the T1 experiment:" ] }, { "cell_type": "code", "execution_count": null, "id": "fdf8914e", "metadata": {}, "outputs": [], "source": [ "trace_example = dataset_gridded.q0_traces.sel(\n", " repetitions=123, t1_time=dataset_gridded.t1_time[-1]\n", ")\n", "trace_example.shape, trace_example.dtype" ] }, { "cell_type": "markdown", "id": "6d5a1035", "metadata": {}, "source": [ "Now we can plot these digitized signals for each quadrature. For clarity, we plot only\n", "part of the signal." ] }, { "cell_type": "code", "execution_count": null, "id": "20686f92", "metadata": {}, "outputs": [], "source": [ "trace_example_plt = trace_example[:200]\n", "trace_example_plt.real.plot(figsize=(15, 5), marker=\".\", label=\"I-quadrature\")\n", "trace_example_plt.imag.plot(marker=\".\", label=\"Q-quadrature\")\n", "plt.gca().legend()\n", "plt.show()" ] } ], "metadata": { "file_format": "mystnb", "jupytext": { "text_representation": { "extension": ".md", "format_name": "myst" } }, "kernelspec": { "display_name": "python3", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 5 }